﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Skugo.Core;
using Skugo.Shared;
using System.Windows;
using ChartUi = System.Windows.Controls.DataVisualization.Charting.Chart;
using System.Windows.Controls.DataVisualization.Charting;
using System.Windows.Media;
using System.Windows.Data;
using System.Collections.ObjectModel;
using System.Windows.Controls;
using System.Windows.Input;
using AvalonDock;

namespace Skugo.StandardPlugins
{
    public class Chart : DockablePlugin
    {
        /// <summary>
        /// The type of message we send or receieve.
        /// </summary>
        enum MessageType : byte
        {
            ClearAllValues,
            NewValue,
            SetMaxValues,
            SetChartType,
            ValueSelected,
            ValueDoubleClicked,
        }

        enum ChartType
        {
            BarsVertical,
            BarsHorizontal,
            Pie,
            LineThin,
            LineArea,
        }

        private ChartUi Ui;

        private UInt32 MaxValues = UInt32.MaxValue;

        private ObservableCollection<KeyValuePair<Object, Object>> Values = new ObservableCollection<KeyValuePair<Object, Object>>();

        protected override void Initialize(BinaryReader reader)
        {
            base.Initialize(reader);

            // Create the chart ui
            this.Ui = new ChartUi();
            this.Ui.Background = Brushes.White;
            this.Ui.Margin = new Thickness(0);
            this.Ui.Padding = new Thickness(10, 0, 0, 0);

            // Setting data for column chart
            this.Ui.DataContext = this.Values;

            this.Content = this.Ui;

            this.InitializeToChartType(ChartType.BarsVertical);
        }

        protected override void OnReceive(Byte[] data)
        {
            var incoming = data.ToBinaryReader();

            var messageType = (MessageType)incoming.ReadByte();

            switch (messageType)
            {
                case MessageType.ClearAllValues:
                {
                    this.Values.Clear();
                    break;
                }

                case MessageType.NewValue:
                {
                    var pair = new KeyValuePair<Object, Object>
                    (
                        incoming.ReadPrimitiveDynamic(),
                        incoming.ReadPrimitiveDynamic()
                    );

                    this.Values.Add(pair);

                    if (this.Values.Count > this.MaxValues)
                    {
                        this.Values.RemoveAt(0);
                    }
                    break;
                }

                case MessageType.SetMaxValues:
                {
                    this.MaxValues = incoming.ReadUInt32();

                    while (this.Values.Count > this.MaxValues)
                    {
                        this.Values.RemoveAt(0);
                    }
                    break;
                }

                case MessageType.SetChartType:
                {
                    var type = (ChartType)incoming.ReadByte();
                    this.InitializeToChartType(type);
                    break;
                }

                default:
                    throw new Exception("Unhandled message type!");
            }
        }

        private static DataPointSeries CreateChart(ChartType type)
        {
            switch (type)
            {
                case ChartType.BarsVertical:
                    return new ColumnSeries();

                case ChartType.BarsHorizontal:
                    return new BarSeries();

                case ChartType.Pie:
                    return new PieSeries();

                case ChartType.LineThin:
                    return new LineSeries();

                case ChartType.LineArea:
                    return new AreaSeries();
            }

            return null;
        }

        private void InitializeToChartType(ChartType type)
        {
            var series = CreateChart(type);
            series.DependentValuePath = "Value";
            series.IndependentValuePath = "Key";
            series.SetBinding(ColumnSeries.ItemsSourceProperty, new Binding());

            // Create the chart ui
            this.Ui.Series.Clear();
            this.Ui.Series.Add(series);

            series.IsSelectionEnabled = true;
            series.SelectionChanged += this.OnSelectionChanged;
            series.MouseDoubleClick += this.OnMouseDoubleClick;
        }

        void OnMouseDoubleClick(Object sender, MouseButtonEventArgs e)
        {
            // Grab the series for this event
            var series = (DataPointSeries)sender;

            // Create a memory stream to write data to
            MemoryStream stream = new MemoryStream();

            // Create a binary writer to write the data
            BinaryWriter outgoing = new BinaryWriter(stream);

            // Write out a the ready message
            outgoing.Write((Byte)MessageType.ValueDoubleClicked);

            outgoing.WritePrimitiveDynamic(series.SelectedItem);

            this.Send(stream.ToArray());
        }

        void OnSelectionChanged(Object sender, SelectionChangedEventArgs e)
        {
            // Grab the series for this event
            var series = (DataPointSeries)sender;

            if (series.SelectedItem == null)
                return;

            // Create a memory stream to write data to
            MemoryStream stream = new MemoryStream();

            // Create a binary writer to write the data
            BinaryWriter outgoing = new BinaryWriter(stream);

            // Write out a the ready message
            outgoing.Write((Byte)MessageType.ValueSelected);

            outgoing.WritePrimitiveDynamic(series.SelectedItem);

            this.Send(stream.ToArray());
        }
    }


}
